#ifndef IA32PROCESSORSTATE_H
#define IA32PROCESSORSTATE_H


#include <iostream>
#include "crossbit/ProcessorState.h"

namespace crossbit {

    class IA32ProcessorState : public ProcessorState
    {
        public:
            IA32ProcessorState() {
                p_tls = 6;
                // add by suntingtao 2008-12-13
                fpu_top = (XTMemAddr)(fpu_stack) + 128;
                                
                for( int i = 0 ; i < EOR ; i++ ) r_[i] = 0;

                for( int i = 0 ; i < 36 ; i++ ) fpr_[i] = 0;
            }
            

            /* total 12 internal registers numbered 0, 1, 2 ..., 11 */
            enum IA32 {
                /* 8 general purpose register */
                EAX = 0, ECX, EDX, EBX, ESP, EBP, ESI, EDI, 
                //Segment Register
                ES,CS,SS,DS,FS,GS,

                PC,
                // reserved for lazy evaluation of condition code
                // add by chuchao,we only choose to emulate the six FLAGS below which are in common use.
                CF,OF,SF,ZF,AF,PF,DF,
                //XXX   
                FControl,FStatus,Ftag,

                REG1, SEG_BASE,TTT, 
                EOR // end of register
            };

            enum X87 {
                //XXX
                FD0,FD1,FD2,FD3,FD4,FD5,FD6,FD7,
                FEOR
            };

            // add by suntingtao , 2008-12-13
            XTMemAddr getFPUStackTop() {
                return fpu_top;
            }

            void setFPUStackTop( XTMemAddr addr ){
                if( addr < (XTMemAddr)(fpu_stack) || addr > (XTMemAddr)(fpu_stack) + 128) {
                    printf("Error in IA32ProcessorState.h : setFPUStackTop\n");
                    assert(0);
                } else {
                    fpu_top = addr;
                }
            }

            virtual MemAddr get(RegNum reg) const
            {
                return (MemAddr) &r_[reg];
            }

            virtual MemAddr fpget(RegNum reg) const
            {
                return (MemAddr) &fpr_[ 3 * reg];
            }

            XTInt32 reg(RegNum reg) const
            {
												    // printf("in ia32: xxxxxxxxxx\n");
                return r_[reg];
            }

            Word fpreg(RegNum reg) const
            {
                return fpr_[3 * reg];
            }

            inline void put(RegNum reg, Word value) 
            {
                r_[reg] = value;
            }

            void fpput(RegNum reg, Word value) 
            {
                fpr_[reg] = value;
            }

            int size() const
            {
                return 8;
            }

            int fpsize() const
            {
                return 12;
            }
            /*
               int set_tls( struct user_desc *desc )
               {
               desc->entry_number = p_tls;
               memcpy( &tls[p_tls-6], desc, sizeof(struct user_desc) );
               p_tls++;
               return 0;
               }

               int get_tls( struct user_desc *desc )
               {
               memcpy( desc, &tls[desc->entry_number-6], sizeof(struct user_desc) );
               return 0;
               }
             */
            void dump() 
            {
                std::cout << "IA32 Register File Dump: " << std::endl
                    << "\tEAX: 0x" << std::hex << r_[0] << std::endl
                    << "\tECX: 0x" << std::hex << r_[1] << std::endl
                    << "\tEDX: 0x" << std::hex << r_[2] << std::endl
                    << "\tEBX: 0x" << std::hex << r_[3] << std::endl
                    << "\tESP: 0x" << std::hex << r_[4] << std::endl
                    << "\tEBP: 0x" << std::hex << r_[5] << std::endl
                    << "\tESI: 0x" << std::hex << r_[6] << std::endl
                    << "\tEDI: 0x" << std::hex << r_[7] << std::endl

                    << "\tES: 0x" << std::hex << r_[8] << std::endl
                    << "\tCS: 0x" << std::hex << r_[9] << std::endl
                    << "\tSS: 0x" << std::hex << r_[10] << std::endl
                    << "\tDS: 0x" << std::hex << r_[11] << std::endl
                    << "\tFS: 0x" << std::hex << r_[12] << std::endl
                    << "\tGS: 0x" << std::hex << r_[13] << std::endl

                    << "\tCF: " << r_[15]  << std::endl
                    << "\tOF: " << r_[16] << std::endl
                    << "\tSF: " << r_[17] << std::endl
                    << "\tZF: " << r_[18] << std::endl;
		/*
                for( int i = 0 ; i < 16  ; i++ ){
                    printf("\tfpu[%d] = %x\n" , i / 2 * 2 , fpr_[i]  );
                }
		*/
		int size = fpsize();
		for (int i = 0; i < size; i++)
		{
		    XTInt32 *p = (XTInt32 *)fpget(i);
		    printf("$f%d: %08x%08x%08x\t", i, *p, *(p+1), *(p+2));

		    if (i % 2 == 1)
			printf("\n");
		}
            }

        private:
            Word r_[EOR];
            Word fpr_[36];
            // QWord fpr_[FEOR];
            //          struct user_desc tls[3];
            // add by stt , 2008-12-13 , to emulate the FPU data register stack 
            XTUint8 fpu_stack[128];
            // get the top of the fpu_stack at the beginning , the fpu_top = fpu_stack + 128;
            XTMemAddr fpu_top;

            int p_tls;
    };
}

#endif
